<?php
/**
 * 用户需求房源推送
 */

namespace app\crontab\controller\always;


use app\common\lib\RespCode;
use custom\Log;
use custom\Redis;
use push\Aurora2;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\Db;
use think\Exception;

class UserAutoPush extends Command {

    private static $hook_list = [];//队列任务
    private static $hooked = false;

    protected function configure() {
        $this->setName('UserAutoPush');
    }

    protected function execute(Input $input, Output $output) {
        $this->initial();
    }

    public function initial() {
        try {
            echo "starting\n";
            //经纪人ID
            $agentIds = db('company_agent_user')
                ->group('agent_id')
                ->where('agent_id', '>', 0)
                ->column('agent_id');
            $agentIds = db('company_agent')
                ->where('id', 'in', $agentIds)
                ->where('deleted', 0)
                ->column('id');
            if (empty($agentIds)) throw new Exception("无需处理", RespCode::PARAMS_ERR);
            //循环经纪人id
            foreach ($agentIds as $k1 => $v1) {
                //跟这个经纪人绑定的多个用户
                $user_ids = db('company_agent_user')
                    ->where('agent_id', $v1)
                    ->where('status', 2)
                    ->column('user_id');
                //循环用户id
                foreach ($user_ids as $k2 => $v2) {
                    //处理用户需求
                    $houseId = self::mergeDemand($v2, $v1);
                    //推送房源消息
                    self::pushRecommendHouse($v2, $v1, $houseId);
                    self::push($v1, $houseId);
                    if ($houseId){
                        $this->addUserHouseMsg($v2, $v1, $houseId,1);
                    }
                }
            }
            echo "正在推送。。。\n";
            $redis = Redis::getInstance();
            $pushData = $redis->keys('push_*');
            foreach ($pushData as $val) {
                $agentId = substr($val, strpos($val, '_') + 1, strlen($val) - strpos($val, '_'));
                $cids = Aurora2::getCid($agentId);
                //registration_id不为空
                $registration_id = db("company_agent")->where('id', $agentId)->value('registration_id');
                if (!empty($registration_id)) {
                    $ex = $redis->get($val);
                    $ex = explode('-', $ex);
                    if ($ex[1] > 0) {
                        //推送
                        if (!Aurora2::push($cids[0], $registration_id, '我们已为您的' . $ex[0] . '个客户总共推荐' . $ex[1] . '套房源。点击查看', Aurora2::TYPE2))
                            Log::write('推送失败:' . $registration_id, "UserAutoPush_Err.log");
                    }
                }
            }
            //清空push_*
            self::delredis();
            echo "end\n";
        } catch (Exception $e) {
            Db::close();
            $err = "异常信息:{$e->getMessage()} | 异常所在的代码行:{$e->getFile()} | 异常文件{$e->getFile()} | php 版本 " . PHP_VERSION . "(" . PHP_OS . ")";
            Log::write($err, "UserAutoPush_Err.log");
        }
    }


    /**
     * 存放推送映射关系
     * @param $uid
     * @param $data
     */
    public static function push($id, $data) {
        //有房源消息
        $redis = Redis::getInstance();
        // <经纪人,用户数-房源数> 映射关系
        $get = $redis->get('push_' . $id);
        if (!$get) {
            $redis->set('push_' . $id, 1 . '-' . count($data));
        } else {
            $get = explode('-', $get);
            $user_num = $get[0] + 1;//用户数累计
            $house_num = $get[1] + count($data);//房源数累计
            $redis->set('push_' . $id, $user_num . '-' . $house_num);
        }
    }

    /**
     * 删除push_*
     */
    public static function delredis() {
        $redis = Redis::getInstance();
        $pushData = $redis->keys('push_*');
        foreach ($pushData as $val) {
            $redis->del($val);
        }
    }

    /**
     * 处理需求
     * @param $uId
     * @param $code
     * @return array
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function mergeDemand($uId, $agent_id) {
        //最后一个需求
        $after = db('agent_user_demand')
            ->where('user_id', $uId)
            ->whereRaw('self_write = 1 or agent_id = ' . $agent_id)
            ->order('utime', 'desc')
            ->limit(1)
            ->select();
        $houseId = self::matchHouse($after);
        return $houseId;
    }

    /**
     * 匹配房源
     * @param $res
     * @return array
     */
    public static function matchHouse($res) {
        $merge = [];
        foreach ($res as $v) {
            $map = [];
            $map[] = ['h.is_shelf', '=', 1];//上架
            $map[] = ['h.deleted', '=', 0];//未删除
            $map[] = ['ha.auction_status', 'in', [1, 2]];//待开始、进行中
            //区域
            if ($v['type'] == 1) {//不限
                if (empty($v['area_code'])) {
                    $p_codes = Db::name('region')->where('city_code', $v['city_code'])->value('p_codes');
                    $codes = $p_codes . $v['city_code'] . ',';
                    $map[] = ['h.city_codes', 'like', trim($codes) . '%'];
                } else {
                    $map[] = ['h.city_code', 'in', $v['area_code']];
                }
            }
            if ($v['type'] == 2) {//小区
                $map[] = ['h.village_id', '=', $v['type_id']];
            }
            if ($v['type'] == 3) {//商圈
                $map[] = ['h.business_area_id', '=', $v['type_id']];
            }
            //价格区间
            $map[] = createSectionQuery1($v['price_section'], 'ha.initial_price');
            //面积区间
            $map[] = createSectionQuery1($v['area_section'], 'h.build_area');
            //户型
            if ($v['door_section']) $map[] = createSectionQuery1($v['door_section'], 'h.bedroom');
            $res = db('house')
                ->alias('h')
                ->join('erp_house_auction ha', 'h.auction_id = ha.id', 'LEFT')
                ->where($map)
                ->column('h.id');
            $merge = array_merge($merge, $res);
        }
        $data = empty($merge) ? [] : array_keys(array_flip($merge));
        return $data;
    }

    /**
     * 推送房源消息
     * @param $uid
     * @param $ids
     * @param $data
     * @throws Exception
     * @throws \think\exception\PDOException
     */
    public static function pushRecommendHouse($uid, $agent_id, $data) {
        return db("company_agent_user")
            ->where('user_id', $uid)
            ->where('status', 2)
            ->where('is_demand', 1)
            ->where('agent_id', $agent_id)
            ->update(['recommend_house' => empty($data) ? '' : join(',', $data)]);
    }

//    ------------------------------

    /**
     * 当用户进行定制选房需求修改，需要向APP经纪人端推送对应房源套数。
     * 这个方法必须通过fastcgi模式调用
     * @param $uId
     */
    public function editDemand($uId) {
        try {
            $redisModel = Redis::getInstance();
            $redisModel->lpush("edit_demand_list", $uId);
            self::hook([$this, 'edit_demand_list'], []);
        } catch (Exception $e) {
            Db::close();
            $err = "异常信息:{$e->getMessage()} | 所在的代码行:{$e->getFile()} | 文件{$e->getFile()} | php 版本 " . PHP_VERSION . "(" . PHP_OS . ")";
            Log::write($err, "UserAutoPush_Err.log");
        }
    }

    /**
     * hook函数fastcgi_finish_request执行
     * @param callback $callback
     * @param array $params
     */
    public static function hook($callback, $params) {
        self::$hook_list[] = ['callback' => $callback, 'params' => $params];
        if (self::$hooked == false) {
            self::$hooked = true;
            register_shutdown_function([__CLASS__, 'sync']);
        }
    }

    /**
     * 由系统调用
     * @return void
     */
    public static function sync() {
        fastcgi_finish_request();
        set_time_limit(0);
        ini_set('memory_limit', '-1');
        if (empty(self::$hook_list)) exit();
        foreach (self::$hook_list as $hook) {
            $callback = $hook['callback'];
            $params = $hook['params'];
            call_user_func_array($callback, $params);
        }
    }

    /**
     * 消耗 队列
     * @param $params
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    function edit_demand_list() {
        $redisModel = Redis::getInstance();
        $i = 0;
        $co = $redisModel->lRange('edit_demand_list', 0, -1);
        while ($i < count($co)) {
            $rdata = $redisModel->brPop("edit_demand_list", 5);
            if ($rdata) {
                self::dealEditDemand($rdata[1]);
            }
            $i++;
            if ($i == $co) break;
        }
        exit();
    }

    /**
     * 给经纪人推送修改了需求的用户
     * @param $uId
     * @return bool
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public function dealEditDemand($uId) {
        //自己填的
        $after = db('agent_user_demand')
            ->where('user_id', $uId)
            ->where('self_write', 1)
            ->select();
        if (empty($after)) {
            Log::write('用户' . $uId . '没有自填需求', "UserAutoPush_Err.log");
            return false;
        }
        $house_ids = self::matchHouse($after);
        //用户对应的专属经纪人
        $data = db('company_agent_user')
            ->alias('cau')
            ->join('company_user cu', 'cu.id=cau.user_id')
            ->where('cau.status', 2)
            ->where('cau.user_id', $uId)
            ->field('cau.agent_id,cau.remark,cu.nickname')
            ->select();
        if (empty($data)) {
            Log::write('未找到用户对应的专属经纪人', "UserAutoPush_Err.log");
            return false;
        }
        foreach ($data as $v) {
            db("company_agent_user")
                ->where('agent_id', $v['agent_id'])
                ->where('user_id', $uId)
                ->update(['recommend_house' => $recommend_house = count($house_ids) > 0 ? join(',', $house_ids) : '']);
            if ($house_ids){
                $this->addUserHouseMsg($uId,$v['agent_id'],$house_ids,2);//添加用户消息通知
            }
            $cids = Aurora2::getCid($v['agent_id']);
            $count = count($house_ids);
            if (!empty($registration_id = db("company_agent")
                    ->where('id', $v['agent_id'])
                    ->value('registration_id')) && $count > 0) {
                //推送
                $name = empty($v['remark']) ? base64_decode($v['nickname']) : $v['remark'];
                if (!Aurora2::push($cids[0], $registration_id, "你的客户【{$name}】选房需求已更新，为其匹配了【{$count}】套房源，赶快去分享拓客吧！", Aurora2::TYPE2))
                    Log::write('推送失败:设备号->' . $registration_id, "UserAutoPush_Err.log");
            }
        }

    }

    /**
     * 添加用户消息通知表数据
     * @param int $user_id
     * @param int $agent_id
     * @param string $house_ids
     */
    public function addUserHouseMsg($user_id=0,$agent_id=0,$house_ids=[],$type=1){
        $count=0;
        if ($house_ids){
            $count=count($house_ids);
        }
        $add['title']=$type==1?"我们已为该客户推荐{$count}套房源":"该客户更新需求，为其推荐{$count}套房源";
        $add['house']=$house_ids?implode(',',$house_ids):'';
        $add['user_id']=$user_id;
        $add['agent_id']=$agent_id;
        $add['is_read']=0;
        $add['itime']=time();
        db('message_agent_user_house')->insert($add);

    }

}
